#! /usr/bin/python
#
# repcacheman ver 0.44
#
# Cache Manager for Http-Replicator
# deletes duplicate files in PORTDIR.
# imports authenticated (checksum + listed in portage)
# files from PORTDIR to replicator's cache directory.
#
# Uses portage to perform checksum and database functions.
# All else, Copyright(C)2004-2007 Tom Poplawski (poplawtm@earthlink.net)
# Distributed under the terms of the GNU General Public License v2
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.

# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.


import portage.manifest
import portage.checksum
import portage.exception
import portage
import string
import os
import pwd,sys,optparse

if os.getuid():
	print"Must be root"
	sys.exit(1)

# Parse Options

parser = optparse.OptionParser()
parser.add_option('-d', '--dir', type='string', default="/var/cache/http-replicator", help='http-replicators cache DIR')
parser.add_option('-u','--user', type='string', default="portage", help='http-replicator USER')
options, args = parser.parse_args() # parse command line

if options.user:
	try:
		uid=pwd.getpwnam(options.user)[2]
		gid=pwd.getpwnam(options.user)[3]
	except:
		print "User \'" + options.user + "\' Doesn't exist on system - edit config or add user to system."
		sys.exit(1)
else:
	print "Error\n\tunable to get USER from /etc/http-replicator.conf"
	sys.exit(1)

# dir is replicator's cache directory
dir=options.dir+"/"

if os.path.isdir(dir) :
	newdir=0
else :
	print"\n\nBegin Http-Replicator Setup...."
	try:
		os.makedirs(dir)
		print "\tcreated " + dir
		newdir=1
	except:
		print "\tcreate " + dir + " failed"
		print '\terror:', sys.exc_info()[1]
		sys.exit(1)
	try:
		os.chown(dir,uid,gid)
		print "\tchanged owner of " + dir + " to " + options.user 
	except:
		print "\tchange owner " + dir + " to " + options.user + " failed:"
		print '\terror:', sys.exc_info()[1]

print "\n\nReplicator's cache directory: " + dir

# Import Portage settings

distdir=portage.settings["DISTDIR"]+"/"
if distdir:
	print "Portage's DISTDIR: " + distdir
else:
	print"Unable to get Portage's DISTDIR"
	sys.exit(1)

# Start Work

print "\nComparing directories...."

# Create filecmp object
import filecmp
dc=filecmp.dircmp (distdir,dir,['cvs-src','git-src','hg-src','egit-src','.locks'])
print "Done!"

dupes=dc.common
deleted=0

if dupes:
	print "\nDeleting duplicate file(s) in " + distdir

	for s in dupes:
		print s
		try:
			os.remove(distdir + s )
			deleted +=1
		except:
			print "\tdelete " + distdir + s + " failed:"
			print '\terror:', sys.exc_info()[1]

	print "Done!"


newfiles=dc.left_only
nf=len(dc.left_only)

if nf:
	print "\nNew files in DISTDIR:"
	for s in newfiles:
		print s
	print"\nChecking authenticity and integrity of new files..."
	added=0
	errors=0
	badsum=0

# search all packages 

	for mycp in portage.db["/"]["porttree"].dbapi.cp_all():
		manifest = portage.manifest.Manifest("/usr/portage/" + mycp , distdir)
		if manifest == None:
			portage.writemsg("Missing manifest: %s\n" % mycpv)

		remove=[]
		for file in newfiles:
			if manifest.hasFile("DIST",file):
				try:
					myok, myreason = manifest.checkFileHashes("DIST",file)
					
					try:
						os.rename(distdir+file,dir+file)
						added += 1
					except:
						try:
							import shutil
							shutil.copyfile(distdir+file,dir+file)
							added += 1
							os.remove(distdir+file)
						except:
							print "\tmove/copy " + file + " failed:"
							print '\terror:', sys.exc_info()[1]
							errors+=1
							
					try:
						os.chown(dir+file,uid,gid)
					except:
						print "\tchown " + file + " failed:"
						print '\terror:', sys.exc_info()[1]
						errors +=1
						
					remove.append( file )
					
				except portage.exception.DigestException, e:
					print("\n!!! Digest verification failed:")
					print("!!! %s" % e.value[0])
					print("!!! Reason: %s" % e.value[1])
					print("!!! Got: %s" % e.value[2])
					print("!!! Expected: %s" % e.value[3])
					badsum+=1
		if remove:
			for rf in remove:
				newfiles.remove ( rf )


print "\nSUMMARY:"
print "Found " + str(len(dupes)) + " duplicate file(s)"
if deleted:
	print "\tDeleted " + str(deleted) + " dupe(s)"

if nf:
	print "Found " + str(nf) + " new file(s)"
	print "\tAdded " + str(added) + " of those file(s) to the cache"
	
	print "Rejected " +str(len(newfiles))  + " File(s) - ",
	print str(badsum) +  " failed checksum(s)"
	for s in newfiles:
		print "\t%s" %s
	if errors:
		print "Encountered " +str(errors) + " errors"
#	if badsum:
#		print str(badsum) + " partial/corrupted file(s)"

if newdir:
	print"\n\nexecute:\n/etc/init.d/http-replicator start"
	print"to run http-replicator.\n\nexecute:\nrc-update add http-replicator default"
	print"to make http-replicator start at boot"
	print"\n\nexecute:\n/usr/bin/repcacheman\nafter emerge's on the server to delete"
	print"dup files and add new files to the cache"

print "\n\nHTTP-Replicator requires you delete any partial downloads in " + distdir
print "run rm -f " + distdir +'*'

